package com.tansun.tandata.service.impl;

import java.util.*;
import java.util.stream.Collectors;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.tansun.tandata.entity.Menu;
import com.tansun.tandata.mapper.MenuDao;
import com.tansun.tandata.service.MenuService;
import com.tansun.tandata.utils.CodeGenerator;
import com.tansun.tandata.utils.Constants;
import com.tansun.tandata.utils.ParentServiceImp;
import com.tansun.tandata.vo.req.MenuVO;
import com.tansun.tandata.vo.req.TreeVo;
import com.tansun.tandata.vo.res.MenuNewVO;
import com.tansun.tandata.vo.res.MenuWithParentVO;
import com.tansun.tandata.vo.res.RoleCodeApiVO;
import com.tansun.tandata.vo.res.RoleInfoByRoleCodesVO;

/**
 * @Description 菜单信息业务类
 * @CreateDate 20200429
 * @author shenxiaodong
 * @Version v1.0
 *
 */
@Service
public class MenuServiceImpl extends ParentServiceImp<MenuDao, Menu> implements MenuService {

	@Autowired
	private MenuDao menuDao;

	/**
	 * 查询角色对应菜单信息
	 * @return List<Role>
	 */
	public List<String> selectMenuByRoleCode(String roleCode){
		return menuDao.selectMenuByRoleCode(roleCode);
	}

	/**
	 * 查询角色对应菜单的api信息
	 * @return List<Role>
	 */
	public List<RoleInfoByRoleCodesVO> selectMenuApiByRoleCode(){
		List<RoleInfoByRoleCodesVO> roleInfoByRoleCodesVOList = new ArrayList<>();
		RoleInfoByRoleCodesVO roleInfoByRoleCodesVO;
		List<RoleCodeApiVO> roleCodeApiVOList = menuDao.selectMenuApiByRoleCode();
		//取出所有
		for (RoleCodeApiVO roleCodeApiVO : roleCodeApiVOList) {
			roleInfoByRoleCodesVO = new RoleInfoByRoleCodesVO();
			roleInfoByRoleCodesVO.setRoleCode(roleCodeApiVO.getRoleCode());
			roleInfoByRoleCodesVO.setApis(Arrays.asList(roleCodeApiVO.getRsrcNos().split(",")));
			roleInfoByRoleCodesVOList.add(roleInfoByRoleCodesVO);
		}
		return roleInfoByRoleCodesVOList;
	}

	/**
	 * 根据角色编号查询菜单
	 */
	@Override
	public List<MenuNewVO> getMenuInfosByRoleCodes(String roleCodes) {
		List<MenuNewVO> menuList;
		//2、通过角色信息取到菜单目录
		Set<Menu> menuSet = new TreeSet<>((o1, o2) -> {
			if(o1 == null || o2 == null) {
				return 1;
			}
			return o1.getId().compareTo(o2.getId());
		});
		//如果数据库存在的是Api路径而不一定会有对应的菜单路径，会导致的菜单不全
		Arrays.stream(roleCodes.split(",")).forEach(roleCode -> {
			List<Menu> list = menuDao.selectMenuInfoByRoleCode(roleCode);
			if(!CollectionUtils.isEmpty(list)) {
				menuSet.addAll(list);
			}
			//对于方法并没有在role_menu关联上级菜单
			List<Menu> listParent = menuDao.selectParentMenuInfoByRoleCode(roleCode);
			if(!CollectionUtils.isEmpty(listParent)) {
				menuSet.addAll(listParent);
			}
		});
		//3.菜单集合取交集，加上所有父菜单
		if(!CollectionUtils.isEmpty(menuSet)) {
			//获取父节点id，有菜单时增加父节点
			Set<String> parents = menuSet.stream().map(Menu::getPrntId).collect(Collectors.toSet());
			for(String parentId : parents ) {
				menuSet.add(menuDao.selectMenuInfoById(parentId));
			}
		}
		//递归变化
		menuList = loadMenu(new ArrayList<>(menuSet));
		return menuList;
	}


	/**
	 * 查询所有菜单信息
	 * @return List<Role>
	 */
	public List<TreeVo> selectAllMenu(){
		String parentOrg = Constants.CHAR_STRING_ZERO;
		List<Menu> menus = menuDao.selectAllMenu();
		return buildTreeAll(menus, parentOrg);
	}

	/**
	 * 递归遍历机构
	 * @param menus 机构集合
	 * @param parentOrg 父code
	 */
	public List<TreeVo> buildTreeAll(List<Menu> menus, String parentOrg) {
		List<TreeVo> treeVoList = new ArrayList<>();
		TreeVo treeVo;
		for (Menu menu : menus) {
			if(menu.getPrntId().equals(parentOrg)) {
				List<TreeVo> childList = buildTreeAll(menus, menu.getId());
				treeVo = new TreeVo();
				treeVo.setCode(menu.getId());
				treeVo.setLabel(menu.getFnChnNm());
				treeVo.setSort(menu.getSort());
				treeVo.setChildren(childList);
				treeVoList.add(treeVo);
			}
		}
		if (treeVoList.size() > 1){
			treeVoList.sort((o1, o2) -> {
				if (o1.getSort() == null){
					return -1;
				}else if (o2.getSort() == null){
					return 1;
				}
				return o1.getSort() - o2.getSort();
			});
		}
		return treeVoList;
	}

	/**
	 * 新增菜单
	 */
	@Transactional(readOnly = false)
	public void saveMenu(MenuVO menuVO) {
		Menu menu = new Menu();
		BeanUtils.copyProperties(menuVO, menu);
		menu.setId(CodeGenerator.getUUID(Menu.class));
		menu.setCreater(getCurrUserId());
		menu.setCreateTime((new Date()));
		menu.setIsDelete(Constants.DELETE_FLAG_RESERVED);
		menu.setUpdateCount(Constants.USER_UPDATE_COUNT_INIT);
		menuDao.saveMenu(menu);
		//新增菜单(角色并无此权限)后如果父菜单已被关联则应该取消，逐级取消
		if (!"0".equals(menu.getPrntId())){
			deleteRoleMenuIfParentExist(menu.getPrntId());
		}
	}

	/**
	 * 在角色菜单表中删除已关联的父菜单
	 */
	private void deleteRoleMenuIfParentExist(String menuId){
		menuDao.deleteRoleMenuById(menuId);
		Menu menu = menuDao.selectMenuInfoById(menuId);
		if (!"0".equals(menu.getPrntId())){
			deleteRoleMenuIfParentExist(menu.getPrntId());
		}
	}

	/**
	 * 根据名称获取菜单
	 */
	public int getMenuByChnNameOrEngName(String fnChnNm, String fnEngNm, String id) {
		return menuDao.getMenuByChnNameOrEngName(fnChnNm, fnEngNm, id);
	}

	/**
	 * 根据id查询带父菜单信息
	 */
	public MenuWithParentVO selectMenuWithParentInfoById(String id) {
		Menu menu = menuDao.selectMenuInfoById(id);
		MenuWithParentVO menuWithParentVO = new MenuWithParentVO();
		menuWithParentVO.setId(menu.getId());
		menuWithParentVO.setPrntId(menu.getPrntId());
		Menu menuParent = menuDao.selectMenuInfoById(menu.getPrntId());
		if (menuParent == null){
			menuWithParentVO.setPrntFnChnNm(null);
		}else {
			menuWithParentVO.setPrntFnChnNm(menuParent.getFnChnNm());
		}
		menuWithParentVO.setFnChnNm(menu.getFnChnNm());
		menuWithParentVO.setFnEngNm(menu.getFnEngNm());
		menuWithParentVO.setFnCtgrCd(menu.getFnCtgrCd());
		menuWithParentVO.setRsrcNo(menu.getRsrcNo());
		return menuWithParentVO;
	}

	/**
	 * 修改菜单
	 */
	public void updateMenu(MenuVO menuVO) {
		//用户属性赋值
		Menu menu = new Menu();
		BeanUtils.copyProperties(menuVO, menu);
		menu.setUpdater(getCurrUserId());
		menu.setUpdateTime(new Date());
		menuDao.updateMenu(menu);
	}

	/**
	 * 通过id获取菜单信息
	 */
	public void deleteMenuById(String id) {
		menuDao.deleteMenuById(id);
		menuDao.deleteRoleMenuById(id);
	}

	/**
	 * 递归菜单
	 */
	private  List<MenuNewVO> loadMenu(List<Menu> menuList){
		if(CollectionUtils.isEmpty(menuList)) {
			return null;
		}
		String rootId = Constants.CHAR_TREE_ZERO;
//		//构建页面所需路由菜单
//		List<Menu> firMenuInfos = new ArrayList<>();
//		List<Menu> secMenuInfos = new ArrayList<>();
//		for(Menu menuInfo : menuList) {
//			if(menuInfo != null && rootId.equals(menuInfo.getPrntId())) {
//				firMenuInfos.add(menuInfo);
//			}else {
//				secMenuInfos.add(menuInfo);
//			}
//		}

		List<MenuNewVO> menuNewVOs = changeMenu(menuList);
//		List<MenuNewVO> firstLevelMenu = changeMenu(firMenuInfos);
//		List<MenuNewVO> secondLevelMenu = changeMenu(secMenuInfos);
//		for(MenuNewVO parent : firstLevelMenu) {
//			for(MenuNewVO child : secondLevelMenu) {
//				setChildrenMenu(parent,child);
//			}
//		}

		return buildTree(menuNewVOs,Constants.CHAR_STRING_ZERO);
	}

	/**
	 * 转化为页面菜单
	 */
	private  List<MenuNewVO> changeMenu(List<Menu> targetMenu){
		String rootId = Constants.CHAR_STRING_ZERO;
		List<MenuNewVO> result = new ArrayList<>();
		for(Menu menuInfo : targetMenu) {
			if(menuInfo == null) {
				continue;
			}
			MenuNewVO menuNewVO = new MenuNewVO();
			menuNewVO.setIdVal(menuInfo.getId());
			menuNewVO.setPathUrl("/" +menuInfo.getFnEngNm());//path
			menuNewVO.setTitleName(menuInfo.getFnChnNm());//路由title
			menuNewVO.setMuName(menuInfo.getFnEngNm());// 路由name
			if(!rootId.equals(menuInfo.getPrntId())) {
				menuNewVO.setMuUrl(menuInfo.getRsrcNo());//component url
			}else {
				if("system".contains(menuInfo.getFnEngNm())) {
					menuNewVO.setMIcon("sys");//一级菜单(系统管理)设置默认图标
				}
				if("dataInfo".contains(menuInfo.getFnEngNm())) {
					menuNewVO.setMIcon("data");//一级菜单(数据管理)设置默认图标
				}
				if("reportInfo".contains(menuInfo.getFnEngNm())) {
					menuNewVO.setMIcon("chart");//一级菜单(图表)设置默认图标
				}
			}
			menuNewVO.setSort(menuInfo.getSort());//增加排序字段
			menuNewVO.setId(menuInfo.getId());
			menuNewVO.setParentId(menuInfo.getPrntId());
			result.add(menuNewVO);
		}
		return result;
	}

	/**
	 *
	 * 递归遍历菜单
	 *
	 * @param menuNewVOs 菜单集合
	 * @param currentCode 父code
	 */
	public List<MenuNewVO> buildTree(List<MenuNewVO> menuNewVOs,String currentCode) {
		List<MenuNewVO> childMenuNewVOs = new ArrayList<>();
		for (MenuNewVO menuNewVO : menuNewVOs) {
			if(menuNewVO.getParentId().equals(currentCode)) {
				List<MenuNewVO> childList = buildTree(menuNewVOs,menuNewVO.getId());
				menuNewVO.setChildrens(childList);
				childMenuNewVOs.add(menuNewVO);
			}
		}
		if (childMenuNewVOs.size() > 1){
			childMenuNewVOs.sort((o1, o2) -> {
				if (o1.getSort() == null){
					return -1;
				}else if (o2.getSort() == null){
					return 1;
				}
				return o1.getSort() - o2.getSort();
			});
		}
		return childMenuNewVOs;
	}

	/**
	 * 递归生产子菜单
	 * @param parent 父菜单
	 * @param child 子菜单
	 */
	private void setChildrenMenu(MenuNewVO parent, MenuNewVO child) {
		if(parent.getId().equals(child.getParentId())) {
			List<MenuNewVO> list = parent.getChildrens();
			list.add(child);
			parent.setChildrens(list);
		}else if(parent.getChildrens().size() > 0) {
			for(MenuNewVO bean : parent.getChildrens()) {
				setChildrenMenu(bean,child);
			}
		}
	}
}
